#include <iostream>      // 输入输出流库
#include <filesystem>    // 文件系统操作库(C++17)
#include <fstream>       // 文件流操作库
#include <vector>        // 动态数组容器
#include <memory>        // 智能指针相关
#include <algorithm>     // 算法库(如排序、查找等)
#include <stdlib.h>      // 标准库函数(如exit)
#include <unordered_map> // 哈希表容器

#include <nlohmann/json.hpp>           // JSON解析库
#include <rapidfuzz/rapidfuzz_all.hpp> // 字符串相似度计算库

#include <cppconn/driver.h>             // MySQL C++连接器驱动
#include <cppconn/exception.h>          // MySQL异常类
#include <cppconn/resultset.h>          // MySQL结果集
#include <cppconn/statement.h>          // MySQL语句
#include <cppconn/prepared_statement.h> // MySQL预处理语句
#include <mysql_driver.h>               // MySQL驱动
#include <execution>                    // 并行算法支持(C++17)
#include <mutex>

// 数据库处理类
class DatabaseHandler
{
private:
    sql::mysql::MySQL_Driver *driver; // MySQL驱动指针
    sql::Connection *con;             // 数据库连接指针
    nlohmann::json config;            // 配置信息(JSON格式)

    // 检查并创建数据库(如果不存在)
    void check_and_create_database()
    {
        // 准备查询语句，检查数据库是否存在
        sql::PreparedStatement *pstmt = con->prepareStatement(
            "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?");
        pstmt->setString(1, config["dbName"].get<std::string>());

        // 执行查询并获取结果
        std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

        // 如果数据库不存在，则创建
        if (!res->next())
        {
            sql::Statement *stmt = con->createStatement();
            stmt->execute("CREATE DATABASE " + config["dbName"].get<std::string>());
            std::cout << "Database created: " << config["dbName"].get<std::string>() << std::endl;
            delete stmt;
        }
        delete pstmt;
    }

    // 检查并创建表(如果不存在)
    void check_and_create_table()
    {
        // 准备查询语句，检查表是否存在
        sql::PreparedStatement *pstmt = con->prepareStatement(
            "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?");
        pstmt->setString(1, config["dbName"].get<std::string>());
        pstmt->setString(2, config["tableName"].get<std::string>());

        // 执行查询并获取结果
        std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

        // 如果表不存在，则创建
        if (!res->next())
        {
            sql::Statement *stmt = con->createStatement();
            // 创建表
            std::string createTableSQL = "CREATE TABLE " +
                                         config["tableName"].get<std::string>() +
                                         " ("
                                         "id INT AUTO_INCREMENT PRIMARY KEY, "
                                         "student_id VARCHAR(20) NOT NULL UNIQUE, "
                                         "student_name VARCHAR(50) COMMENT '学生姓名', "
                                         "class VARCHAR(20) COMMENT '班级', "
                                         "major ENUM('数据科学与大数据技术','网络工程','智能科学与技术','网络空间安全') NOT NULL COMMENT '专业', "
                                         "git_repo VARCHAR(255) COMMENT 'Git仓库地址', "

                                         // 相似度字段
                                         "lab1_similarity FLOAT DEFAULT 0.0 COMMENT '实验1相似度', "
                                         "lab2_similarity FLOAT DEFAULT 0.0 COMMENT '实验2相似度', "
                                         "lab3_similarity FLOAT DEFAULT 0.0 COMMENT '实验3相似度', "
                                         "lab4_similarity FLOAT DEFAULT 0.0 COMMENT '实验4相似度', "

                                         // 莱文斯坦距离
                                         //  "lab1_levenshtein INT UNSIGNED DEFAULT NULL COMMENT '实验1编辑距离', "
                                         //  "lab2_levenshtein INT UNSIGNED DEFAULT NULL COMMENT '实验2编辑距离', "
                                         //  "lab3_levenshtein INT UNSIGNED DEFAULT NULL COMMENT '实验3编辑距离', "
                                         //  "lab4_levenshtein INT UNSIGNED DEFAULT NULL COMMENT '实验4编辑距离', "

                                         // 实验成绩
                                         "lab1_score TINYINT UNSIGNED DEFAULT 0 CHECK (lab1_score <= 100) COMMENT '实验1成绩', "
                                         "lab2_score TINYINT UNSIGNED DEFAULT 0 CHECK (lab2_score <= 100) COMMENT '实验2成绩', "
                                         "lab3_score TINYINT UNSIGNED DEFAULT 0 CHECK (lab3_score <= 100) COMMENT '实验3成绩', "
                                         "lab4_score TINYINT UNSIGNED DEFAULT 0 CHECK (lab4_score <= 100) COMMENT '实验4成绩', "

                                         // 实验用时
                                         "lab1_time SMALLINT UNSIGNED DEFAULT 0 COMMENT '实验1用时(秒)', "
                                         "lab2_time SMALLINT UNSIGNED DEFAULT 0 COMMENT '实验2用时(秒)', "
                                         "lab3_time SMALLINT UNSIGNED DEFAULT 0 COMMENT '实验3用时(秒)', "
                                         "lab4_time SMALLINT UNSIGNED DEFAULT 0 COMMENT '实验4用时(秒)', "

                                         // 索引
                                         "INDEX idx_major (major), "
                                         "INDEX idx_class (class), "
                                         "INDEX idx_student_id (student_id)"
                                         ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生实验成绩表'";

            stmt->execute(createTableSQL);
            std::cout << "Table created: " << config["tableName"].get<std::string>() << std::endl;
            delete stmt;
        }
        else
        {
            std::cout << "Table already exists: " << config["tableName"].get<std::string>() << std::endl;
        }
        delete pstmt;
    }

public:
    // 构造函数，初始化数据库连接
    DatabaseHandler(const nlohmann::json &configuration) : config(configuration)
    {
        // 获取MySQL驱动实例
        driver = sql::mysql::get_mysql_driver_instance();
        // 创建数据库连接
        con = driver->connect(
            config["addr"].get<std::string>(),
            config["user"].get<std::string>(),
            config["password"].get<std::string>());
    }

    // 析构函数，释放资源
    ~DatabaseHandler()
    {
        if (con)
            delete con;
    }

    // 设置数据库(创建数据库和表)
    void setup_database()
    {
        check_and_create_database();
        con->setSchema(config["dbName"].get<std::string>());
        check_and_create_table();
    }

    // 将SSH地址转换为HTTPS（仅处理Gitee）
    std::string convert_git_ssh_to_https(const std::string &ssh_url)
    {
        // 示例SSH: git@gitee.com:username/repo.git
        // 目标HTTPS: https://gitee.com/username/repo.git
        if (ssh_url.find("git@gitee.com:") == 0)
        {
            return "https://gitee.com/" + ssh_url.substr(14);
        }
        return ssh_url; // 如果不是Gitee SSH格式，原样返回
    }

    // 专业英文名到中文ENUM值的映射
    std::string map_major_to_chinese(const std::string &major)
    {
        static const std::map<std::string, std::string> majorMap = {
            {"Data Science and Big Data Technology", "数据科学与大数据技术"},
            {"Network Engineering", "网络工程"},
            {"Intelligent Science and Technology", "智能科学与技术"},
            {"Cyberspace Security", "网络空间安全"}};

        auto it = majorMap.find(major);
        return (it != majorMap.end()) ? it->second : "数据科学与大数据技术"; // 默认值
    }

    // 插入或更新学生数据（基本信息只设置一次，成绩可多次更新）
    void insert_or_update(const nlohmann::json &student, int lab,
                          double similarity, 
                          //int levenshtein,
                          int score, int time_used)
    {
        // 转换Git地址和专业
        std::string git_repo = convert_git_ssh_to_https(student["git"].get<std::string>());
        std::string major_chinese = map_major_to_chinese(student["major"].get<std::string>());

        // 首先尝试插入基本信息（如果不存在）
        std::string insert_sql = "INSERT IGNORE INTO " + config["tableName"].get<std::string>() +
                                 " (student_id, student_name,class, major, git_repo) "
                                 "VALUES (?, ?, ?, ?, ?)";

        sql::PreparedStatement *insert_stmt = con->prepareStatement(insert_sql);
        insert_stmt->setString(1, student["number"].get<std::string>());
        insert_stmt->setString(2, student["name"].get<std::string>());
        insert_stmt->setString(3, student["class"].get<std::string>());
        insert_stmt->setString(4, major_chinese);
        insert_stmt->setString(5, git_repo);
        insert_stmt->executeUpdate();
        delete insert_stmt;

        // 然后更新实验数据
        std::string update_sql = "UPDATE " + config["tableName"].get<std::string>() +
                                 " SET lab" + std::to_string(lab) + "_similarity = ?, " +
                                 //"lab" + std::to_string(lab) + "_levenshtein = ?, " +
                                 "lab" + std::to_string(lab) + "_score = ?, " +
                                 "lab" + std::to_string(lab) + "_time = ? " +
                                 "WHERE student_id = ?";

        sql::PreparedStatement *update_stmt = con->prepareStatement(update_sql);
        update_stmt->setDouble(1, similarity);
        //update_stmt->setInt(2, levenshtein);
        update_stmt->setInt(2, score);
        update_stmt->setInt(3, time_used);
        update_stmt->setString(4, student["number"].get<std::string>());
        update_stmt->executeUpdate();
        delete update_stmt;
    }
};


// 处理cast文件的类
class CastProcessor
{
private:
    // 特殊键映射表(将控制字符转换为可读字符串)
    static const std::unordered_map<std::string, std::string> SPECIAL_KEYS;

public:

    //将 \uXXXX 转换成真正的字符
    static std::string unescape_unicode(const std::string &s)
    {
        std::string result;
        for (size_t i = 0; i < s.size();)
        {
            if (s[i] == '\\' && i + 1 < s.size() && s[i + 1] == 'u')
            {
                // 解析 \uXXXX
                std::string hex_str = s.substr(i + 2, 4);
                unsigned int hex_val = std::stoul(hex_str, nullptr, 16);
                result += static_cast<char>(hex_val);
                i += 6;
            }
            else
            {
                result += s[i];
                i++;
            }
        }
        return result;
    }

    // 处理cast文件，提取输入记录
    static std::vector<std::string> process_cast_file(const std::filesystem::path &castFile)
    {
        std::vector<std::string> records;
        std::ifstream file(castFile);
        std::string line;
        std::string current_text; // 用于累积普通字符

        while (std::getline(file, line))
        {
            // 快速检查是否符合 [..., "i", ...] 格式
            if (line.find("\"i\"") == std::string::npos)
                continue;

            // 提取第三个字段（简单字符串处理）
            size_t start = line.find_last_of('"');
            if (start == std::string::npos)
                continue;
            size_t end = line.rfind('"', start - 1);
            if (end == std::string::npos)
                continue;

            std::string data = line.substr(end + 1, start - end - 1);


            // 检查是否是特殊键并转换
            auto it = CastProcessor::SPECIAL_KEYS.find(data);
            if (it != CastProcessor::SPECIAL_KEYS.end())
            {
                // 如果有累积的普通字符，先添加
                if (!current_text.empty())
                {
                    records.push_back(current_text);
                    current_text.clear();
                }
                // 添加特殊键
                records.push_back(it->second);
            }
            else
            {
                // 不是特殊键，累积到当前文本
                current_text += data;
            }
        }

        // 处理最后可能剩余的普通字符
        if (!current_text.empty())
        {
            records.push_back(current_text);
        }

        return records;
    }

    static std::string process_terminal_record(const std::vector<std::string> &record) //
    {
        // 定义一个字符串缓冲区，用于存储处理后的文本
        std::string buffer;
        // 光标当前位置，初始为0
        size_t cursor_pos = 0;
        // 当前行的起始位置，初始为0
        size_t current_line_start = 0;
        // 记录所有换行符位置的数组
        std::vector<size_t> line_breaks; // 记录所有换行符位置

        // 定义一个映射表，将操作字符串映射到对应的lambda函数
        const std::unordered_map<std::string, std::function<void()>> actions = {
            // 处理回车键操作
            {"[ENTER]", [&]()
             {
                 // 在光标位置插入换行符
                 buffer.insert(cursor_pos, "\n");
                 // 记录换行符位置
                 line_breaks.push_back(cursor_pos++);
                 // 更新当前行起始位置为光标新位置
                 current_line_start = cursor_pos;
             }},
            // 处理换行键操作（功能与回车相同）
            // {"[NEWLINE]", [&]()
            //  {
            //      buffer.insert(cursor_pos, "\n");
            //      line_breaks.push_back(cursor_pos++);
            //      current_line_start = cursor_pos;
            //  }},
            // 处理制表键操作
            // {"[TAB]", [&]()
            //  {
            //      // 插入4个空格
            //      buffer.insert(cursor_pos, "    ");
            //      // 光标向右移动4位
            //      cursor_pos += 4;
            //  }},
            // 处理退格键操作
            {"[BACKSPACE]", [&]()
             {
                 // 如果光标不在最左端
                 if (cursor_pos > 0)
                 {
                     // 如果前一个字符是换行符
                     if (buffer[cursor_pos - 1] == '\n')
                     {
                         // 在换行符数组中查找并删除该换行符记录
                         auto it = std::find(line_breaks.begin(), line_breaks.end(), cursor_pos - 1);
                         if (it != line_breaks.end())
                         {
                             line_breaks.erase(it);
                         }
                     }
                     // 删除前一个字符
                     buffer.erase(--cursor_pos, 1);
                 }
             }},
            // 处理左箭头键操作
            {"[LEFT]", [&]()
             {
                 // 如果光标不在最左端，向左移动一位
                 if (cursor_pos > 0)
                     cursor_pos--;
             }},
            // 处理右箭头键操作
            {"[RIGHT]", [&]()
             {
                 // 如果光标不在最右端，向右移动一位
                 if (cursor_pos < buffer.length())
                     cursor_pos++;
             }},
            // 处理上箭头键操作
            {"[UP]", [&]()
             {
                 // 找到当前行的起始位置
                 size_t line_start = current_line_start;
                 for (size_t pos = cursor_pos; pos > 0; --pos)
                 {
                     if (buffer[pos - 1] == '\n')
                     {
                         line_start = pos;
                         break;
                     }
                 }

                 // 如果不是第一行
                 if (line_start > 0)
                 {
                     // 找到上一行的结束位置（当前行起始位置-1）
                     size_t prev_line_end = line_start - 1;
                     // 初始化上一行起始位置为0
                     size_t prev_line_start = 0;
                     // 查找上一行的起始位置
                     for (size_t pos = prev_line_end; pos > 0; --pos)
                     {
                         if (buffer[pos - 1] == '\n')
                         {
                             prev_line_start = pos;
                             break;
                         }
                     }

                     // 计算当前行中的光标偏移量
                     size_t offset_in_line = cursor_pos - line_start;
                     // 计算上一行的长度
                     size_t prev_line_length = prev_line_end - prev_line_start;
                     // 移动光标到上一行的对应位置
                     cursor_pos = prev_line_start + std::min(offset_in_line, prev_line_length);
                 }
             }},
            // 处理下箭头键操作
            {"[DOWN]", [&]()
             {
                 // 找到下一行的起始位置
                 size_t next_line_start = buffer.length();
                 for (size_t pos = cursor_pos; pos < buffer.length(); ++pos)
                 {
                     if (buffer[pos] == '\n')
                     {
                         next_line_start = pos + 1;
                         break;
                     }
                 }

                 // 如果下一行存在
                 if (next_line_start < buffer.length())
                 {
                     // 找到下一行的结束位置
                     size_t next_line_end = buffer.length();
                     for (size_t pos = next_line_start; pos < buffer.length(); ++pos)
                     {
                         if (buffer[pos] == '\n')
                         {
                             next_line_end = pos;
                             break;
                         }
                     }

                     // 计算当前行的起始位置
                     size_t line_start = current_line_start;
                     for (size_t pos = cursor_pos; pos > 0; --pos)
                     {
                         if (buffer[pos - 1] == '\n')
                         {
                             line_start = pos;
                             break;
                         }
                     }

                     // 计算当前行中的光标偏移量
                     size_t offset_in_line = cursor_pos - line_start;
                     // 计算下一行的长度
                     size_t next_line_length = next_line_end - next_line_start;
                     // 移动光标到下一行的对应位置
                     cursor_pos = next_line_start + std::min(offset_in_line, next_line_length);
                 }
             }},
            // 处理ESC键操作（不做任何处理）
            // {"[ESC]", [&]() { /* 忽略ESC */ }}
            };

        // 遍历所有输入的操作
        for (const auto &op : record)
        {
            // 如果操作在映射表中存在
            if (actions.find(op) != actions.end())
            {
                // 执行对应的操作函数
                actions.at(op)();
            }
            else
            {
                // 如果不是特殊操作，直接插入文本
                buffer.insert(cursor_pos, op);
                // 移动光标到插入文本之后
                cursor_pos += op.length();
            }
        }

        // 过滤输出结果，只保留换行符、制表符和可打印ASCII字符
        std::string filtered_result;
        for (char c : buffer)
        {
            // 检查字符是否是换行符、制表符或在可打印ASCII范围内
            if (c == '\n' || c == '\t' || (c >= 32 && c <= 126))
            {
                filtered_result += c;
            }
        }

        // 返回过滤后的结果
        return filtered_result;
    }

    // 检查UTF-8编码字符串与库中文件的相似度
    static double check_similarity_utf8(const std::vector<std::string> &input_record, const std::filesystem::path &castLibDir)
    {
        // 首先将所有输入序列拼接成一个字符串
        std::string record;
        for (const auto &input : input_record)
        {
            record += input;
        }

        std::vector<std::filesystem::path> txt_files;
        std::mutex max_mutex;
        double max_similarity = 0.0;

        // 先收集所有txt文件路径
        for (const auto &entry : std::filesystem::directory_iterator(castLibDir))
        {
            if (entry.is_regular_file() && entry.path().extension() == ".txt")
            {
                txt_files.push_back(entry.path());
            }
        }

        // 如果没有找到任何文件，返回0相似度
        if (txt_files.empty())
        {
            return 0.0;
        }

        // 并行处理每个文件
        std::for_each(std::execution::par, txt_files.begin(), txt_files.end(),
                      [&](const std::filesystem::path &file_path)
                      {
                          std::ifstream file(file_path);
                          if (file.is_open())
                          {
                              // 读取文件内容(UTF-8编码)
                              std::string content((std::istreambuf_iterator<char>(file)),
                                                  std::istreambuf_iterator<char>());

                              // 计算相似度
                              double current_similarity = rapidfuzz::fuzz::ratio(record, content);

                              // 使用互斥锁保护最大相似度更新
                              std::lock_guard<std::mutex> lock(max_mutex);
                              if (current_similarity > max_similarity)
                              {
                                  max_similarity = current_similarity;
                              }
                          }
                      });

        return max_similarity;
    }

    static double get_time(const std::string &filename)
    {
        std::ifstream file(filename);
        if (!file.is_open())
        {
            throw std::runtime_error("无法打开文件: " + filename);
        }

        std::string line, prevValidLine, secondLastValidLine;
        int validLineCount = 0;

        // 读取文件并记录最后两个有效行
        while (std::getline(file, line))
        {
            if (!line.empty()) // 跳过空行
            {
                secondLastValidLine = prevValidLine;
                prevValidLine = line;
                validLineCount++;
            }
        }

        // 检查是否有足够的有效行
        if (validLineCount < 2)
        {
            throw std::runtime_error("文件需要至少2行有效数据");
        }

        // 提取倒数第二行的第一个数字
        std::istringstream iss(secondLastValidLine);
        double timestamp;

        // 尝试读取第一个数字
        if (!(iss >> timestamp))
        {
            // 如果直接读取失败，尝试跳过非数字前缀
            iss.clear();
            char ch;
            while (iss.get(ch))
            {
                if (std::isdigit(ch) || ch == '-' || ch == '+')
                {
                    iss.putback(ch);
                    if (iss >> timestamp)
                    {
                        return timestamp;
                    }
                    break;
                }
            }
            throw std::runtime_error("无法从行中提取数字: " + secondLastValidLine);
        }

        return timestamp;
    }
};

//特殊键映射表定义
const std::unordered_map<std::string, std::string> CastProcessor::SPECIAL_KEYS = {
    {"\r", "[ENTER]"},
    {"\x7f", "[BACKSPACE]"}, // 真正的退格符 (0x7F)
    {"\x1b", "[ESC]"},       // ESC (0x1B)
    {"\x1b[A", "[UP]"},      // UP 键序列
    {"\x1b[B", "[DOWN]"},    // DOWN 键序列
    {"\x1b[C", "[RIGHT]"},   // RIGHT 键序列
    {"\x1b[D", "[LEFT]"},    // LEFT 键序列
    {"\x1bOA", "[UP]"},      // 另一种 UP 表示
    {"\x1bOB", "[DOWN]"},    // 另一种 DOWN 表示
    {"\x1bOC", "[RIGHT]"},   // 另一种 RIGHT 表示
    {"\x1bOD", "[LEFT]"},    // 另一种 LEFT 表示
};

// 根据学生目录和实验号获取cast文件路径
std::filesystem::path get_cast_file_path(const std::filesystem::path &studentDir, int lab)
{
    switch (lab)
    {
    case 1:
        return studentDir / "lab1" / "lab1.cast";
    case 2:
        return studentDir / "lab2" / "lab2.cast";
    case 3:
        return studentDir / "lab3" / "lab3.cast";
    case 4:
        return studentDir / "lab4" / "lab4.cast";
    default:
        throw std::invalid_argument("Invalid lab number");
    }
}

// 主函数
int main(int argc, char *argv[])
{
    if (argc < 3)
    {
        std::cout << "实验号，学生git仓库，cast库目录" << std::endl;
        return 1;
    }

    // 获取命令行参数
    int labNumber;
    std::string lab=argv[1];
    if(lab=="lab1"){
        labNumber = 1;
    }else if (lab=="lab2")
    {
        labNumber = 2;
    }
    else if (lab == "lab3")
    {
        labNumber = 3;
    }
    else if (lab == "lab4")
    {
        labNumber = 4;
    }else{
        return -1;
    }
    

    std::filesystem::path studentDir = argv[2]; // 学生目录
    std::filesystem::path castLibDir = argv[3];     // cast库目录
    // int labNumber = 1;                          // 实验号
    // 处理cast文件
    std::filesystem::path castFile = get_cast_file_path(studentDir, labNumber);
    std::vector<std::string> castStr = CastProcessor::process_cast_file(castFile);
    // for (const auto &r : castStr)
    // {
    //     std::cout << "Extracted: " << r << std::endl;
    // }
    //  计算相似度
    double similarity = CastProcessor::check_similarity_utf8(castStr, castLibDir);

    double time = CastProcessor::get_time(castFile);
    std::cout << "time: "<< similarity <<std::endl;

    // 读取学生信息和数据库配置
    std::fstream studentJsonFile(studentDir / "student.json");

    std::fstream mysqlJsonFile("config.json");

    nlohmann::json studentJson = nlohmann::json::parse(studentJsonFile);

    nlohmann::json mysqlJson = nlohmann::json::parse(mysqlJsonFile);


    // 处理数据库操作
    // DatabaseHandler dbHandler(mysqlJson);

    // dbHandler.setup_database();

    // dbHandler.insert_or_update(studentJson, labNumber, similarity, 10, time);


    return 0;
}